﻿using Microsoft.Phone.BackgroundAudio;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Windows.Controls.Primitives;
using System.Xml.Linq;
using Samples.Radio.Agent.Model;
using WindowsPhoneAudioStreaming.Audio.Streaming;

namespace Samples.Radio.Agent
{
    public static class ExtensionMethods
    {
        /// <summary>
        /// Helper method to convert values of now playing in xml to a boolean
        /// </summary>
        /// <param name="convertToNowPlayingBoolean"></param>
        /// <returns></returns>
        public static bool ConvertToIsNowPlaying(this string convertToNowPlayingBoolean)
        { 
            if(convertToNowPlayingBoolean.Equals("now", StringComparison.InvariantCultureIgnoreCase))
            {
                return true;
            }

            return false;
        }


        public static PlaylistTrack[] ToPlaylist(this IEnumerable<AudioStreamDefinition> radioTrackDefintions)
        {
            return (from track in radioTrackDefintions
                    where track != null
                    select new PlaylistTrack
                    {
                        Id = Guid.NewGuid(),
                        Title = track.Title,
                        Source = track.StreamUri,
                        AlbumArtUrl = track.ImageUri,
                        IsStreaming = true,
                        PlayerControls = EnabledPlayerControls.Pause
                    }).ToArray();
        }
    }

    public static class Utilities
    {
        public static T DoActionWithListBoxSelection<T>(this object sender, Action<T> action) where T : class
        {
            var list = sender as Selector;
            if (list == null) return default(T);
            var selection = list.SelectedItem as T;
            if (selection == null) return default(T);
            list.SelectedIndex = -1;
            action(selection);
            return selection;
        }

        private static bool? isInDesignMode;
        public static Random Random = new Random();

        public static bool IsInDesignMode
        {
            get
            {
                if (!isInDesignMode.HasValue)
                {
                    isInDesignMode = DesignerProperties.IsInDesignTool;
                }
                return isInDesignMode.Value;
            }
        }

        public static string SafeElementValue(this XElement element, string name)
        {
            if (element == null || element.Element(name) == null) return null;
            var xElement = element.Element(name);
            return xElement != null ? xElement.Value : null;
        }

        public static string SafeElementValue(this XElement element, XName name)
        {
            if (element == null || element.Element(name) == null) return null;
            var xElement = element.Element(name);
            return xElement != null ? xElement.Value : null;
        }


        public static string SafeAttributeValue(this XElement element, XName name)
        {
            if (element == null || element.Attribute(name) == null) return null;
            var xAttribute = element.Attribute(name);
            return xAttribute != null ? xAttribute.Value : null;
        }

        public static string SafeAttributeValue(this XElement element, string name)
        {
            if (element == null || element.Attribute(name) == null) return null;
            var xAttribute = element.Attribute(name);
            return xAttribute != null ? xAttribute.Value : null;
        }

        public static TValue SafeDictionaryValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            return dictionary.SafeDictionaryValue<TKey, TValue, TValue>(key);
        }

        public static TReturn SafeDictionaryValue<TKey, TValue, TReturn>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            if (dictionary == null) return default(TReturn);
            TValue val;
            if (dictionary.TryGetValue(key, out val))
            {
                if (val is TReturn)
                {
                    return (TReturn)(object)val;
                }
            }
            return default(TReturn);

        }

        public static double ToDouble(this string doubleValue, double defaultValue = 0.0)
        {
            if (String.IsNullOrWhiteSpace(doubleValue)) return defaultValue;
            double retValue;
            if (Double.TryParse(doubleValue, out retValue)) return retValue;
            return defaultValue;
        }

        public static DateTime ToDate(this string doubleValue, string customFormat = null)
        {
            if (String.IsNullOrWhiteSpace(doubleValue)) return DateTime.Now;
            DateTime retValue;
            if (!string.IsNullOrWhiteSpace(customFormat))
            {
                if (DateTime.TryParseExact(doubleValue, customFormat, CultureInfo.CurrentCulture, DateTimeStyles.None, out retValue)) return retValue;
            }
            if (DateTime.TryParse(doubleValue, out retValue)) return retValue;
            return DateTime.Now;
        }
        public static bool ToBool(this string boolValue)
        {
            if (String.IsNullOrWhiteSpace(boolValue)) return false;
            bool retValue;
            if (bool.TryParse(boolValue, out retValue)) return retValue;
            return false;
        }

        public static int ToInt(this string intValue, int defaultValue = 0)
        {
            if (String.IsNullOrWhiteSpace(intValue)) return defaultValue;
            int retValue;
            if (Int32.TryParse(intValue, out retValue)) return retValue;
            return defaultValue;
        }

        public static T EnumParse<T>(this string enumValue, bool ignoreCase = true) where T : struct
        {
            try
            {
                if (String.IsNullOrEmpty(enumValue)) return default(T);
                return (T)Enum.Parse(typeof(T), enumValue, ignoreCase);
            }
            catch
            {
                return default(T);
            }
        }

        public static void SafeRaise<TParameter1>(this EventHandler<ParameterEventArgs<TParameter1>> handler, object sender, TParameter1 args)
        {
            handler.SafeRaise(sender, new ParameterEventArgs<TParameter1>(args));
        }
        public static void SafeRaise<TParameter1, TParameter2>(this EventHandler<DualParameterEventArgs<TParameter1, TParameter2>> handler, object sender, TParameter1 arg1, TParameter2 arg2)
        {
            handler.SafeRaise(sender, new DualParameterEventArgs<TParameter1, TParameter2>(arg1, arg2));
        }
        public static void SafeRaise<TParameter1, TParameter2, TParameter3>(this EventHandler<TripleParameterEventArgs<TParameter1, TParameter2, TParameter3>> handler, object sender, TParameter1 arg1, TParameter2 arg2, TParameter3 arg3)
        {
            handler.SafeRaise(sender, new TripleParameterEventArgs<TParameter1, TParameter2, TParameter3>(arg1, arg2, arg3));
        }

        public static void SafeRaise(this EventHandler handler, object sender, EventArgs args = null)
        {
            if (args == null)
            {
                args = EventArgs.Empty;
            }
            if (handler != null)
                handler(sender, args);
        }

        public static void SafeRaise<T>(this EventHandler<T> handler, object sender, T args)
            where T : EventArgs
        {
            if (handler != null)
                handler(sender, args);
        }


        public static T ReadObject<T>(this DataContractJsonSerializer serializer, Stream strm)
        {
            var obj = serializer.ReadObject(strm);
            if (obj is T) return (T)obj;
            return default(T);
        }

        public static TProp Prop<TObject, TProp>(this TObject obj, Func<TObject, TProp> prop)
        {
            if (obj == null) return default(TProp);
            return prop(obj);
        }

        public static void DoForEach<T>(this IEnumerable<T> source, Action<T> action)
        {
            foreach (var item in source)
            {
                action(item);
            }
        }

        public static TList Fill<TList, T>(this TList source, IEnumerable<T> items) where TList : IList<T>
        {
            if (items != null)
            {
                foreach (var item in items)
                {
                    source.Add(item);
                }
            }
            return source;
        }

        public static TList Replace<TList, T>(this TList source, IEnumerable<T> newItems) where TList : IList<T>
        {
            source.Clear();
            source.Fill(newItems);
            return source;
        }
    }

    /// <summary>
    /// Event args with one strongly typed parameter
    /// </summary>
    public class ParameterEventArgs<T> : EventArgs
    {
        public T Parameter1 { get; set; }

        public ParameterEventArgs(T parameter)
        {
            Parameter1 = parameter;
        }

        /// <summary>
        /// Converts the parameter into a ParameterEventArgs
        /// </summary>
        public static implicit operator ParameterEventArgs<T>(T parameter)
        {
            return new ParameterEventArgs<T>(parameter);
        }
    }

    /// <summary>
    /// Event args with two strongly typed parameters
    /// </summary>
    public class DualParameterEventArgs<T1, T2> : ParameterEventArgs<T1>
    {
        public T2 Parameter2 { get; set; }

        public DualParameterEventArgs(T1 parameter1, T2 parameter2)
            : base(parameter1)
        {
            Parameter2 = parameter2;
        }

        /// <summary>
        /// Converts the parameter into a ParameterEventArgs
        /// </summary>
        public static implicit operator DualParameterEventArgs<T1, T2>(object[] parameters)
        {
            if (parameters == null || parameters.Length != 2) return null;
            return new DualParameterEventArgs<T1, T2>((T1)parameters[0], (T2)parameters[1]);
        }
    }

    /// <summary>
    /// Event args with three strongly typed parameters
    /// </summary>
    public class TripleParameterEventArgs<T1, T2, T3> : DualParameterEventArgs<T1, T2>
    {
        public T3 Parameter3 { get; set; }

        public TripleParameterEventArgs(T1 parameter1, T2 parameter2, T3 parameter3)
            : base(parameter1, parameter2)
        {
            Parameter3 = parameter3;
        }

        /// <summary>
        /// Converts the parameter into a ParameterEventArgs
        /// </summary>
        public static implicit operator TripleParameterEventArgs<T1, T2, T3>(object[] parameters)
        {
            if (parameters == null || parameters.Length != 3) return null;
            return new TripleParameterEventArgs<T1, T2, T3>((T1)parameters[0], (T2)parameters[1], (T3)parameters[2]);
        }
    }

}
